using System.Collections.Generic;
using Dimebrain.TweetSharp;
using Dimebrain.TweetSharp.Extensions;
using Dimebrain.TweetSharp.Fluent;
using Dimebrain.TweetSharp.Model;
using KlearTweet.Client.Infrastructure;

namespace KlearTweet.Client.WebServices
{
    public class TwitterClient
    {
        private const int EntitiesToTakePerPage = 25; // TODO: Change to 100?
        private static string _proxy;


        public static void Initialize(IDictionary<string, string> initParams)
        {
            // Use ClientHttp to be able to read the response header
            var httpResult = System.Net.WebRequest.RegisterPrefix("http://", System.Net.Browser.WebRequestCreator.ClientHttp);
            if (!httpResult)
                throw new System.Exception("WebRequest.RegisterPrefix failed"); // This probably means that it was already done somewhere else

            if (initParams.ContainsKey("TwitterClient.Proxy"))
            {
                _proxy = initParams["TwitterClient.Proxy"];
                Storage.Database.SaveParameter("TwitterClient.Proxy", _proxy);
            }
            else // Not available, probably because we are running out-of-browser
                _proxy = Storage.Database.LoadParameter("TwitterClient.Proxy");

            FluentTwitter.SetClientInfo(new TwitterClientInfo
            {
                ClientName = "KlearTweet",
                ClientUrl = "http://www.kleartweet.com",
                ClientVersion = "0.5.0.0",
                TransparentProxy = _proxy,
            });
        }




        public static void SendTweet(Model.Account account, string text, System.Action<string> callBack)
        {
            if (text == null || text.Trim() == string.Empty)
                throw new System.Exception("Tweet text required");

            var twitter = FluentTwitter.CreateRequest()
                .Configuration.UseTransparentProxy(_proxy)
                //.AuthenticateAs("username", "password") // BasicAuth
                // TODO: Client-side OAuth is not supported because the signature must be generated using url=twitter.com (currently, it is done with the proxyUrl)
                .AuthenticateWith(account.ApplicationConsumerKey, "n/a", account.AuthToken, "n/a") // Server-side OAuth
                .Statuses()
                .Update(text)
                //.InReplyToStatus() // TODO
                .AsJson()
                .CallbackTo((s, e) => callBack(e.Response));
            // TODO: Parse response to inject its tweet

            twitter.RequestAsync();
        }



        public static TwitterSearch CreateFriendsTimelineSearch(Model.Account account)
        {
            return new TwitterSearch((sinceId, page) => CreateFriendsTimelineSearch(sinceId, page, account));
        }

        private static ITwitterLeafNode CreateFriendsTimelineSearch(long maxId, int page, Model.Account account)
        {
            var search = FluentTwitter.CreateRequest()
                .Configuration.UseTransparentProxy(_proxy)
                .AuthenticateWith(account.ApplicationConsumerKey, "n/a", account.AuthToken, "n/a")
                .Statuses()
                .OnFriendsTimeline()
                .Take(EntitiesToTakePerPage);

            if (page > 0) // => NextPage
            {
                search.Skip(page);
                if (maxId > 0)
                    search.Before(maxId);
            }
            else if (maxId > 0) // => Refresh
                search.Since(maxId);

            return search.AsJson();
        }


        public static TwitterSearch CreateUserTimelineSearch(Model.Account account)
        {
            return new TwitterSearch((sinceId, page) => CreateUserTimelineSearch(sinceId, page, account));
        }

        private static ITwitterLeafNode CreateUserTimelineSearch(long maxId, int page, Model.Account account)
        {
            var search = FluentTwitter.CreateRequest()
                .Configuration.UseTransparentProxy(_proxy)
                .AuthenticateWith(account.ApplicationConsumerKey, "n/a", account.AuthToken, "n/a")
                .Statuses()
                .OnUserTimeline()
                .Take(EntitiesToTakePerPage);

            if (page > 0) // => NextPage
            {
                search.Skip(page);
                if (maxId > 0)
                    search.Before(maxId);
            }
            else if (maxId > 0) // => Refresh
                search.Since(maxId);

            return search.AsJson();
        }


        public static TwitterSearch CreateTextSearch(string searchText)
        {
            return new TwitterSearch((sinceId, page) => CreateTextSearch(sinceId, page, searchText));
        }

        private static ITwitterLeafNode CreateTextSearch(long maxId, int page, string searchText)
        {
            var search = FluentTwitter.CreateRequest()
                //.Configuration.UseTransparentProxy(_proxy)
                .Search().Query().Containing(searchText)
                .Take(EntitiesToTakePerPage);

            if (page > 0) // => NextPage
            {
                search.Skip(page);
                if (maxId > 0)
                    search.Before(maxId);
            }
            else if (maxId > 0) // => Refresh
                search.Since(maxId);

            return search.AsJson();
        }




        public static void GetAuthorizationUrl(System.Action<string> callBack)
        {
            var twitter = FluentTwitter.CreateRequest()
                .Configuration.UseTransparentProxy(_proxy)
                .Authentication.GetRequestToken("n/a", "n/a")
                .CallbackTo((s, e) => GetAuthorizationUrlCompleted(callBack, e.Response));

            twitter.RequestAsync();
        }


        private static void GetAuthorizationUrlCompleted(System.Action<string> callBack, string response)
        {
            try
            {
                var result = response.AsToken();

                var authorizationUrl = FluentTwitter.CreateRequest()
                    .Authentication.GetAuthorizationUrl(result.Token);

                callBack(authorizationUrl);
            }
            catch (System.Exception ex)
            {
                var error = response.AsError();
                if (error != null)
                    throw new System.Exception(error.ErrorMessage, ex);
                throw new System.Exception("GetAuthorizationUrl failed. Response = " + response, ex);
            }
        }
    }
}